using System;
using System.Collections.Generic;
using System.Text;

using Mud.Common;
using Mud.Common.Physical;

namespace Mud.Client
{
    /// <summary>
    /// Represents the game area where the player, creatures and objects are located.
    /// </summary>
    public class Area
    {

        #region Properties

        /// <summary>
        /// Area name.
        /// </summary>
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        private string _name;

        /// <summary>
        /// List of simple objects in the area.
        /// </summary>
        public IDictionary<int, SimpleObject> SimpleObjects
        {
            get { return _simpleObjects; }
        }
        private Dictionary<int, SimpleObject> _simpleObjects = new Dictionary<int, SimpleObject>();

        /// <summary>
        /// List of creatures in the area.
        /// </summary>
        public IDictionary<int, Creature> Creatures
        {
            get { return _creatures; }
        }
        private Dictionary<int, Creature> _creatures = new Dictionary<int, Creature>();

        /// <summary>
        /// Area land.
        /// </summary>
        public AreaLandSquare[,] Land
        {
            get { return _land; }
        }
        private AreaLandSquare[,] _land;

        public Size Size
        {
            get { return _size; }
        }
        private Size _size;

        #endregion

        #region Public methods


        public void SetLand(AreaLandSquare landSquare)
        {
            Land[landSquare.X, landSquare.Y] = landSquare;
            if (this.AreaChanged != null)
                this.AreaChanged(this, new Location(landSquare.X, landSquare.Y));
        }

        /// <summary>
        /// Adds the creature to the area
        /// </summary>
        /// <param name="c">The creature.</param>
        public void AddCreature(Creature c)
        {
            if (_creatures.ContainsKey(c.ObjectId))
                throw new InvalidOperationException(string.Format("Creature with id {0} is already in the area {1}.", c.ObjectId, Name));
            _creatures.Add(c.ObjectId, c);
            if (CreatureAdded != null)
                CreatureAdded(this, c);
        }

        /// <summary>
        /// Removes the creature from the area
        /// </summary>
        /// <param name="c">The creature.</param>
        public void RemoveCreature(Creature c)
        {
            if (!_creatures.ContainsKey(c.ObjectId))
                throw new InvalidOperationException(string.Format("Creature with id {0} is not in the area {1}.", c.ObjectId, Name));
            _creatures.Remove(c.ObjectId);
            if (CreatureRemoved != null)
                CreatureRemoved(this, c);
        }

        /// <summary>
        /// Removes the creature from the area
        /// </summary>
        /// <param name="objectId">Creature ID.</param>
        public void RemoveCreature(int objectId)
        {
            if (!_creatures.ContainsKey(objectId))
                throw new InvalidOperationException(string.Format("Creature with id {0} is not in the area {1}.", objectId, Name));
            Creature removed = _creatures[objectId];
            _creatures.Remove(objectId);
            if (CreatureRemoved != null)
                CreatureRemoved(this, removed);
        }

        /// <summary>
        /// Adds the object to the area
        /// </summary>
        /// <param name="c">The object.</param>
        public void AddObject(SimpleObject o)
        {
            if (_simpleObjects.ContainsKey(o.ObjectId))
                throw new InvalidOperationException(string.Format("Object with id {0} is already in the area {1}.", o.ObjectId, Name));
            _simpleObjects.Add(o.ObjectId, o);
            if (ObjectAdded != null)
                ObjectAdded(this, o);
        }

        /// <summary>
        /// Removes the object from the area
        /// </summary>
        /// <param name="o">The object.</param>
        public void RemoveObject(SimpleObject o)
        {
            if (!_simpleObjects.ContainsKey(o.ObjectId))
                throw new InvalidOperationException(string.Format("Object with id {0} is not in the area {1}.", o.ObjectId, Name));
            _simpleObjects.Remove(o.ObjectId);
            if (ObjectRemoved != null)
                ObjectRemoved(this, o);
        }


        /// <summary>
        /// Removes the object from the area
        /// </summary>
        /// <param name="objectId">Object ID.</param>
        public void RemoveObject(int objectId)
        {
            if (!_simpleObjects.ContainsKey(objectId))
                throw new InvalidOperationException(string.Format("Object with id {0} is not in the area {1}.", objectId, Name));
            SimpleObject obj = _simpleObjects[objectId];
            _simpleObjects.Remove(objectId);
            if (ObjectRemoved != null)
                ObjectRemoved(this, obj);
        }


        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="T:Area"/> class.
        /// </summary>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        public Area(int width, int height)
        {
            _land = new AreaLandSquare[width, height];
            _size = new Size(width, height);
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    _land[x, y] = new AreaLandSquare();
                }

            }
        }

        #region Area events

        /// <summary>
        /// Raised when area changes.
        /// </summary>
        public event AreaChangedHandler AreaChanged;

        /// <summary>
        /// Raised when a creature is added to the area.
        /// </summary>
        public event AreaCreatureChangeHandler CreatureAdded;

        /// <summary>
        /// Raised when a creature is removed from the area.
        /// </summary>
        public event AreaCreatureChangeHandler CreatureRemoved;

        /// <summary>
        /// Raised when an object is added to the area.
        /// </summary>
        public event AreaObjectChangeHandler ObjectAdded;

        /// <summary>
        /// Raised when an object is removed from the area.
        /// </summary>
        public event AreaObjectChangeHandler ObjectRemoved;


        public delegate void AreaChangedHandler(Area o, Location squareChanged);

        public delegate void AreaCreatureChangeHandler(Area o, Creature c);

        public delegate void AreaObjectChangeHandler(Area o, Object c);

        #endregion

    }
}
